package thread;

import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 线程有序
 */
public class ThreadOrderlyTest {

}

class SemaphoreTest {
    private final int n;
    private static long statTime;

    private final Semaphore aSemaphore = new Semaphore(1);
    private final Semaphore bSemaphore = new Semaphore(0);
    private final Semaphore cSemaphore = new Semaphore(0);

    static Thread threadA = null;
    static Thread threadB = null;
    static Thread threadC = null;

    public SemaphoreTest(int i) {
        n = i;
    }

    public void printA() throws InterruptedException {
        for (int i = 0; i < n; i++) {
            aSemaphore.acquire();
            System.out.println("A");
            bSemaphore.release();
        }
    }

    public void printB() throws InterruptedException {
        for (int i = 0; i < n; i++) {
            bSemaphore.acquire();
            System.out.println("B");
            cSemaphore.release();
        }
        System.out.println("elapse time: "+(System.currentTimeMillis() - statTime));
    }
    public void printC() throws InterruptedException {
        for (int i = 0; i < n; i++) {
            cSemaphore.acquire();
            System.out.println("C");
            aSemaphore.release();
        }
    }

    public static void main(String[] args) {
        SemaphoreTest printAbc = new SemaphoreTest(3);
        Runnable printA = () -> {
            try {
                printAbc.printA();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };
        Runnable printB = () -> {
            try {
                printAbc.printB();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };
        Runnable printC = () -> {
            try {
                printAbc.printC();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };
        threadA = new Thread(printA);
        threadB = new Thread(printB);
        threadC = new Thread(printC);
        statTime = System.currentTimeMillis();
        threadA.start();
        threadB.start();
        threadC.start();
    }
}

class LockSupportTest {
    private final int n;
    private static long statTime;

    public LockSupportTest(int n) {
        this.n = n;
    }

    static Thread threadA = null;
    static Thread threadB = null;
    static Thread threadC = null;

    public void printA() throws InterruptedException {
        for (int i = 0; i < n; i++) {
            LockSupport.park(threadA);
            System.out.print("A");
            LockSupport.unpark(threadB);
        }
    }

    public void printB() throws InterruptedException {
        for (int i = 0; i < n; i++) {
            LockSupport.park(threadB);
            System.out.print("B");
            LockSupport.unpark(threadC);
        }
        System.out.println("elapse time: "+(System.currentTimeMillis() - statTime));
    }

    public void printC() throws InterruptedException {
        for (int i = 0; i < n; i++) {
            LockSupport.park(threadC);
            System.out.print("C");
            LockSupport.unpark(threadA);
        }
    }

    public static void main(String[] args) {
        LockSupportTest lockSupportTest = new LockSupportTest(10_0000); //等价于100000
        Runnable printA = () -> {
            try {
                lockSupportTest.printA();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };
        Runnable printB = () -> {
            try {
                lockSupportTest.printB();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };
        Runnable printC = () -> {
            try {
                lockSupportTest.printC();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };
        threadA = new Thread(printA);
        threadB = new Thread(printB);
        threadC = new Thread(printC);
        statTime = System.currentTimeMillis();
        threadA.start();
        threadB.start();
        threadC.start();

        LockSupport.unpark(threadA);
    }
}

class ConditionTest {
    private static final ReentrantLock rl = new ReentrantLock();
    private static final Condition conditionA = rl.newCondition();
    private static final Condition conditionB = rl.newCondition();
    private static final Condition conditionC = rl.newCondition();

    public void execute(String flag) {
        rl.lock();

        try {
            for (int i = 1 ; i <= 10 ; i++) {
                if ("A".equals(flag)) {
                    System.out.println(Thread.currentThread().getName() + " - " + i);
                    conditionB.signal();
                    conditionA.await();
                }

                if ("B".equals(flag)) {
                    System.out.println(Thread.currentThread().getName() + " - " + i);
                    conditionC.signal();
                    conditionB.await();
                }

                if ("C".equals(flag)) {
                    System.out.println(Thread.currentThread().getName() + " - " + i);
                    conditionA.signal();
                    conditionC.await();
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            rl.unlock();
        }
    }

    public static void main(String[] args) {
        ConditionTest conditionTest = new ConditionTest();
        new Thread(() -> conditionTest.execute("A"), "A").start();

        new Thread(() -> conditionTest.execute("B"), "B").start();

        new Thread(() -> conditionTest.execute("C"), "C").start();
    }
}

class JoinTest {
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            try {
                Thread.sleep(3000);
                System.out.println("A");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread thread2 = new Thread(() -> {
            try {
                Thread.sleep(2000);
                System.out.println("B");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread thread3 = new Thread(() -> {
            try {
                Thread.sleep(1000);
                System.out.println("C");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        thread1.start();
        thread1.join();
        thread2.start();
        thread2.join();
        thread3.start();
    }
}

class WaitNotifyTest {
    private volatile int count = 1;

    public void a() throws InterruptedException {
//        synchronized (WaitNotifyTest.class) {
        synchronized (this) {
            System.out.println("线程A进来了");
            while(count != 1) {
                wait();
            }
            System.out.println("线程A");
            count = 2;
            notifyAll();
        }
    }

    public void b() throws InterruptedException {
//        synchronized (WaitNotifyTest.class) {
        synchronized (this) {
            System.out.println("线程B进来了");
            while(count != 2) {
                wait();
            }
            System.out.println("线程B");
            count = 3;
            notifyAll();
        }
    }

    public void c() throws InterruptedException {
//        synchronized (WaitNotifyTest.class) {
        synchronized (this) {
            System.out.println("线程C进来了");
            while(count != 3) {
                wait();
            }
            System.out.println("线程C");
            count = 1;
            notifyAll();
        }
    }

    public static void main(String[] args) {
        WaitNotifyTest waitNotifyTest = new WaitNotifyTest();

        for (int i = 1 ; i <= 3 ; i++) {
            new Thread(() -> {
                try {
                    waitNotifyTest.a();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();

            new Thread(() -> {
                try {
                    waitNotifyTest.b();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();

            new Thread(() -> {
                try {
                    waitNotifyTest.c();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}